home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1996 April
/
CHIP 1996 aprilis (CD06).zip
/
CHIP_CD06.ISO
/
hypertxt.arj
/
9406
/
386_1.CD
next >
Wrap
Text File
|
1994-11-27
|
21KB
|
428 lines
@VA 80286 és 80386 processzorok valós módú@N
@Vlehetôségei@N
@VModern idôk -- I.@N
Az egyre újabb típusú processzorok megjelenésével
gyakori probléma a leírások hiánya vagy
hiányossága, esetleg félrevezetô volta. Cikksorozatomban
szeretnék az assembly programozást kedvelô olvasóknak
rövid betekintést adni a 80286 és 80386 processzorok
által nyújtott új lehetôségekbe. @K(Tördelési@N
@Kokokból az assembly forrásmintákban a sorvégi@N
@Kkommenteket az utasítások elôtti sorba raktuk, végén@N
@Kkettôsponttal -- a Szerk.)@N
Az alábbiak megértéséhez a 8088 processzor assembly nyelvû
programozásának ismerete szükséges. A 8088-ról már sok
szakkönyv jelent meg magyar nyelven is, így viszonylag jól
dokumentáltnak tekinthetô.
@V***** I. ùjdonságok a 80286 valós módjában *****@N
@VBôvített utasításkészlet@N
@VENTER variables, level@N Magasszintû nyelvek stack
keretének létrehozása. Az utasítás lehetôvé teszi az
egybeágyazott funkciók számára egymás stack területén
elhelyezett lokális változóinak elérését. Mûködése az
alábbi algoritmus alapján megérthetô. FRAME_PTR a
processzor belsô munkaváltozója, amelyben SP átmeneti
tárolását végzi. Ha level értéke nulla, akkor nem
egybeágyazott funkcióról van szó, vagy a rendszer nem
használja ezt a lehetôséget. Ellenkezô esetben a legkülsô
egybeágyazási szint az 1.
@KPUSH BP@N
@K FRAME_PTR = SP@N
@K if level > 0 then@N
@K repeat (level-1)-szer:@N
@K BP = BP - 2@N
@K PUSH WORD PTR [BP]@N
@K end repeat@N
@K PUSH FRAME_PTR@N
@K end if@N
@K BP = FRAME_PTR@N
@K SP = SP - variables@N
Példa az utasítás használatára:
@K; 16 byte méretû lokális@N
@K ; változóterület létrehozása@N
@K ; funkció egybeágyazás@N
@K ; (BP másolás) nélkül:@N
@K ENTER 16,0@N
@VLEAVE@N Az ENTER utasítás által létrehozott stack-keret
törlése visszatérés elôtt. Az átadott paramétereket
magunknak kell kitörölni RET n vagy ADD SP,n utasítás
használatával. ENTER és LEAVE között BP értékét meg kell
ôrizni! Az utasítás mûködése:
@KMOV SP,BP@N
@K POP BP@N
@VBOUND reg16, bounds_address@N Intervallum-vizsgálat
egyetlen utasítással. Ha a vizsgálandó tizenhat bites
regiszter értéke kisebb mint WORD PTR [bounds_address] vagy
nagyobb mint WORD PTR [bounds_address+2], akkor INT 5 jön
létre. Az utasítás a regisztert és a határértékeket
egyaránt elôjelesen értelmezi. Alkalmas tömbök és más
adatterületek címzés elôtti határvizsgálatára. Példa az
utasítás használatára:
@K; Ha DI<[BP+28] vagy@N
@K ; DI>[BP+30], akkor INT 5:@N
@K BOUND DI,[BP+28]@N
@VIMUL dest, r/m, immed@N Åltalánosított szorzó utasítás,
amely alkalmas egy memóriaváltozó vagy regiszter és egy
konstans szorzatának bármely általános regiszterbe való
betöltésére más regiszterek felhasználása nélkül. A szorzás
elôjeles, így minden paramétere elôjelesen éretelmezett.
Dest és r/m operandusok 16 bitesek, míg a konstans érték 8
vagy 16 bites lehet. Ha immed 8 bites, a processzor
automatikus 16 bitre való elôjelkiterjesztést hajt végre.
Ha a szorzás során az eredmény nem tárolt felsô 16 bitje is
értékes jegyeket tartalmazott (nem volt egyenlô az alsó 16
bit elôjelkiterjesztésével), akkor a Carry és az Overflow
bit 1 értékû lesz. Érvényes eredmény esetén mindkét flag
törlôdik. Példa az utasítás használatára:
@KIMUL DI,Y_COORD,320@N
@VOUTS, INS@N E két utasítással az eddig megszokott blokkos
memóriamûveletekhez hasonló I/O mûveletek valósíthatók meg.
OUTS alapértelmezetten DS:[SI] címrôl veszi a DX címû
portra kiküldendô byte-ot vagy szót, INS az ES:[DI] címre
tölti le a DX címû portról beolvasott értéket. SI illetve
DI a direction flag állásától függôen nô vagy csökken az
alkalmazott adathosszal. REP prefixum használható az
utasítás CX-ben megadott számú ismétlésére. Példa az
utasítás használatára:
@KMOV AX,INPUT_SEG@N
@K MOV ES,AX@N
@K MOV DI,OFFSET BUFFER1@N
@K MOV DX,PORT_ADDR@N
@K MOV CX,BLOCK_LEN@N
@K CLD@N
@K REP INSB@N
@VPUSHA@N Az AX, BX, CX, DX, SI, DI, BP, SP regisztereket
elmenti a stackre, a felsorolással megegyezô sorrendben.
Igen hasznos lehet interrupt-kezelô eljárások belépésénél.
Mindig figyeljünk arra, hogy az utasítás a
szegmensregiszterek értékeit nem menti el!
@VPOPA@N A PUSHA utasítással stackre mentett regiszterek
visszatöltése.
@Vùj, többszörös biteltolási lehetôség@N A 80286-nál a
biteltoló utasításokban egynél nagyobb értékû eltolási
konstans is megadható. A konstans 8 bites elôjel nélküli
számként értelmezôdik, emiatt negatív eltolás megadása a
ROR és a ROL kivételével nem jár helyes eredménnyel.
Minden eltolás egy plusz órajelciklust igényel.
Értelmezett és helyesen végrehajtható a nulla eltolás.
Egynél több biteltolás esetén az Overflow flag állása
határozatlan. Példák az utasításra:
@KSHR AX,3@N
@K SHL BP,8@N
@Vùj regiszterek@N
A 80286 új regisztereinek többsége az itt nem tárgyalt
védett módú tárkezeléssel kapcsolatos. Az egyetlen, valós
módban is hasznos regiszter az MSW (Machine Status Word),
amelyben az EM bit (2. bit) beállításával lehetôség nyílik
valós módú 80287 emulációra.
@VVáltozások a stack kezelésében@N
A 80286 védett módú tárkezelése szükségessé tette az
utasítás végrehajtása alatt keletkezô hibák korrekt
kezelését. Mivel ilyen esetben az utasítás végrehajtása nem
folytatható helyesen, a processzor a hibaoknak megfelelô
interruptot aktivizálja. Ezen interruptokat kizárásnak,
angolul exceptionnek nevezzük. A hibakezelés
megkönnyítésére a visszatérési cím a hibás utasításra
mutat. Valós módban ilyen hiba lehet egy értelmezhetetlen
utasítás futtatására tett kísérlet, vagy osztási
túlcsordulás létrejötte. A 8088 processzor a kérdéses
utasítás @Kmögé@N mutató címet helyezte a stackre
visszatérési címként, a 80286-tal ellentétben.
A PUSH SP utasítás 8088-on SP kettôvel csökkentett értékét
helyezte a stackre, míg a 80286 már az eredeti értéket
tárolja. POP SP értelmezése megfelel az adott processzor
PUSH SP-vel tárolt értékének. Ha programunkat 8088-on is
futtatni szeretnénk, és az SP stackre mentése
elkerülhetetlen, akkor használjuk PUSH SP helyett a
következô három utasítást a 8088 féle stack
megvalósítására:
@KPUSH BP@N
@K MOV BP,SP@N
@K XCHG BP,[BP]@N
POP SP helyett használjunk két INC SP utasítást az
esetleges stack-hiba elkerülésére.
@V@KJavítások a 8088-hoz képest@N@V@N
A 8088 nem volt képes a legnagyobb negatív szám (-80H
illetve -8000H) szolgáltatására elôjeles osztás
eredményeként. Ehelyett osztási túlcsordulás jött létre.
Ezt a hibát a 80286-ban kijavították.
Egyes régebbi 8088 processzorok nem tiltották helyesen az
interrupt kéréseket a következô utasítás végrehajtásának
idejére MOV SS,r/m utasítás után, ami stackhibát hozhatott
létre a félig beírt stack-mutató miatt. A 80286-ban a
hibát kijavították.
@VTanácsok a (hatékonyabb) kód írásához@N
A 80286 valós módú szolgáltatásainak fordítását a TASM
illetve MASM fordítókon .286c paranccsal engedélyezni kell.
A 80286 memóriakezelése teljesen 16 bites, így a páratlan
címre helyezett szavas adatok elérési ideje 2 órajellel
hosszabb. Emiatt célszerû szavas adatainkat páros címen
tárolni (TASM/MASM fordítók EVEN vagy ALIGN 2 parancsa),
valamint programunk elején SP értékét párosra beállítani.
Ahol csak lehet, tároljuk változóinkat és adatainkat
regiszterekben. A regiszterek kiosztását bonyolultabb
ciklusokban célszerû papíron megtervezni. Kerüljük a
felesleges PUSH és POP mûveleteket, ahol lehet, mentsünk
regiszterbe. Kerüljük a felesleges ugrásokat, különösen a
nagy ciklusszámú hurkokban. A processzor ilyenkor kénytelen
a teljes 9 byte-os queue-t újra beolvasni. Sokszor célszerû
kis méretû és korlátozott ciklusszámú, de sokszor hívott
cilusainkat LOOP használata helyett többször egymásután
fordítani, például a REPT parancs használatával:
@KREPT 10@N
@K STOSB@N
@K INC AL@N
@K ENDM@N
@V***** II. ùjdonságok a 80386 valós módjában *****@N
@V32 bites regiszterkészlet és aritmetika@N
A 80386 tudása és utasításvégrehajtási sebessége lényegesen
nagyobb elôdeinél. 32 bites regiszterkészlete és belsô
felépítése nagyobb számítási pontosságot és sebességet
jelent a valós módú programoknak is. A 80386 valós módban
@<9406\386_1.GIF>használható regiszterei az ábrán láthatók.@N
Az új 32 bites regiszterek és utasítások a .386c parancs
kiadása után használhatók. Kódszegmenseink definíciójában a
SEGMENT parancs végén mindig használjuk a USE16 paramétert.
A 32 bites regiszterek használata külön cím- és
adathosszváltó prefixummal valósul meg, ami lehetôvé teszi
egyetlen utasításon belül az operandusok hosszának szabad
megválasztását. A hosszváltó prefixek hatására 8 helyett
16, 16 helyett 32 bites adat- vagy címkezelés valósul meg.
A 32 bites regiszterek bármelyike szabadon használható
címzésre akár index-, akár bázisregiszterként. 32 bites
címzés esetén lehetôség van az indexregiszter 1, 2, 4 vagy
8-cal való szorzására a címszámítás során. Ez a
skálafaktor, melyet néhány alábbi példában is láthatunk.
Példák 32 bites adatokat és címeket kezelô utasításokra:
@KMOV EAX,12345678H@N
@K ROR EAX,16@N
@K MOV BL,FS:[EAX]@N
@K MOV [EBX*4],EAX@N
@K MOV DWORD PTR DS:[046CH],0F0FA5A5H@N
@K MOV BX,CS:JUMPTABLE[ECX+ESI*2]@N
@Vùj utasítások@N
@VCWDE@N Az AX regisztert elôjelkiterjeszti az EAX
regiszterbe. 16 bites elôjeles értékek 32 bitessé
alakítására hsználható.
@VCDQ@N Az EAX regisztert elôjelkiterjeszti EDX:EAX 64
bites értékké. Elôjeles 32 bites osztás esetén
használható:
@K; Osztandó elôjeles érték:@N
@K@N
@K MOV EAX,SIGNED_VALUE@N
@K ; Osztó (32 bit):@N
@K MOV EBX,DIVIDER@N
@K ; EAX -> EDX:EAX:@N
@K CDQ@N
@K ; EAX (hányados),EDX (maradék)=(EDX:EAX)/EBX:@N
@K IDIV EBX@N
@VBT r/m,bitnum@N A Carry flagbe másolja r/m bitnum
sorszámú bitjét. A legalacsonyabb bit a 0. sorszámú. Az
utasítás bitnum értékét r/m adathosszával modulo veszi
figyelembe. Bitnum megadható 8 bites regiszterben vagy
direkt értékként.
@VBTR r/m,bitnum@N Mint BT, de vizsgálat után törli a
kérdéses bitet.
@VBTS r/m,bitnum@N Mint BT, de vizsgálat után 1-be állítja
a kérdéses bitet.
@VBTC r/m,bitnum@N Mint BT, de vizsgálat után
komplementálja a kérdéses bitet.
@VBSF reg8,src@N Az utasítás az src 16 vagy 32 bites
memória vagy regiszter operandusában elôforduló alsó
bitszámok felôli elsô egyes bit sorszámát tölti a reg8
nyolc bites regiszterbe. Ha src értéke nulla volt (nincsen
benne egyes bit), akkor ZF=1 lesz és reg8 tartalma
határozatlan. Ellenkezô esetben ZF=0.
@VBSR reg8,src@N Mint BSF, de a magasabb bitektôl (15.
vagy 31.) kezdve keres. A bitek sorszáma nem függ a keresés
irányától.
@VSHLD r/m,reg,bitnum@N Az utasítás r/m 16 vagy 32 bites
operandust balra lépteti bitnum bittel, eközben a belépô
bitekbe reg felsô bitjeit lépteti. Bitnum lehet 8 bites
elôjel nélküli direkt érték, vagy a CL regiszter. Az
utasítás nem változtatja meg a reg tartalmát. R/m és reg
mezôk adathossza azonos kell legyen. A Sign, a Zero és a
Parity jelzôbit az r/m-ben megjelenô eredménynek
megfelelôen állítódik be. Az Overflow flag értéke
határozatlan.
@VSHRD r/m,reg,bitnum@N Mint SHLD, azonban r/m-et jobbra
tolva reg alsó bitjeit lépteti be.
@VMOVSX op1,op2@N Elôjelkiterjesztéssel másolja op2-t
op1-be. Alkalmas 8 bites elôjeles adatok 16 vagy 32
bitessé, illetve 16 bites elôjeles adatok 32 bitessé
bôvítésére. Az utasítás paraméterezési korlátai -- az
eltérô adathosszt kivéve -- azonosak a MOV-éval. Példa az
utasítás használatára:
@K; BL elôjelkiterjesztett bemásolása EAX-be:@N
@K MOVSX EAX,BL@N
@VMOVZX op1,op2@N Mint MOVSX, de zéró bitekkel egészíti ki
op2-t.
@VLSS reg,ptr; LDS reg,ptr; LES reg,ptr; LFS reg,ptr; LGS@N
@Vreg,ptr@N Ezekkel az utasításokkal távoli mutató tölthetô
be egy 16 vagy 32 bites ofszet regiszterbe és egy
szegmensregiszterbe. A mutató 32 vagy 48 bites lehet attól
függôen, hogy ofszet része 16 vagy 32 bites. A két új
szegmensregiszter (FS, GS) ES-sel megegyezôen használható.
Példa az utasítás használatára:
@K; 32 bites töltés START_STACK-bôl SS:SP-be:@N
@K LSS SP,START_STACK@N
@K ; 48 bites töltés DEST_PTR-bôl ES:EDI-be:@N
@K LES EDI,DEST_PTR@N
@K ; 32 bites töltés IMAGEDATA-ból GS:BX-be:@N
@K LGS BX,IMAGEDATA@N
@VIMUL dest, r/m@N Az IMUL utasítás általános formája,
amely lehetôvé teszi dest 16 vagy 32 bites regiszter
elôjeles szorzását azonos adathosszú regiszterrel vagy
memóriaváltozóval. Az utasítás elôjeles számként értelmezi
mindegyik paraméterét. Ha a végeredmény nem ábrázolható
helyesen a megadott célregiszterben, az Overflow és a Carry
jelzôbitet az utasítás egybe állítja. Ellenkezô esetben
mindkét flag törlôdik. Példa az utasításra:
@K; ECX := ECX*EBP:@N
@K IMUL ECX,EBP@N
@VPUSHAD@N Az EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP
regiszterek stackre mentése egyetlen utasítással, a
felsorolással megegyezô sorrendben.
@VPOPAD@N A PUSHAD utasítással stackre mentett regiszterek
visszatöltése.
@VHosszú feltételes ugrások@N A 80386 lehetôvé teszi
feltételes ugrások végrehajtását a teljes aktuális
kódszegmensben, ami megkíméli a programozót a ""Jump out of
range" bosszúságaitól. A LOOP és a JCXZ, valamint összes
változatuk sajnos még mindig csak a rövid ugrást támogatja.
@VSETcc reg8@N Az utasítás egyet tölt reg8 nyolc bites
regiszterbe, ha a cc feltétel (lásd Jcc ugró utasítások)
igaz, ellenkezô esetben az eredmény nulla. Nem használható
a SETCXZ illetve SETECXZ utasítás. Példa az utasításra:
@K; AL=1 NZ, AL=0 Z esetén:@N
@K SETNZ AL@N
@VJECXZ@N JCXZ 32 bites megfelelôje, amely ECX=0 esetén
ugrik.
@VLOOPD@N ECX ciklusszámlálóval mûködö LOOP utasítás.
Használható LOOPDZ, LOOPDNZ, LOOPDE, LOOPDNE variációja is.
@VREP@N Ha a blokk utasítás által használt címek 32 bitesek
(ESI vagy EDI), ciklusszámlálóként automatikusan ECX, mint
32 bites számláló kerül felhasználásra. ECX kiválasztását
az adathossz nem befolyásolja. Példa CX illetve ECX
felhasználására blokkutasításban:
@K; ES:[EDI] címen ECX byte feltöltése AL-lel:@N
@K REP STOS BYTE PTR ES:[EDI]@N
@K ; ES:[DI] címen CX byte feltöltése AL-lel:@N
@K REP STOS BYTE PTR ES:[DI]@N
@VCímhibák@N
32 bites regiszterek címzésre való felhasználásával
lehetôség nyílik arra, hogy az eredô ofszet túlmutasson a
64 Kbyte-os valós módú szegmenshatáron. A szegmenslimit
átlépése elôfordulhat szavas vagy duplaszavas adatcímzés
esetén is, ha az adat bármely byte-ja kívül esik a
szegmenshatáron. Ez jelentôs eltérés a 80286-hoz képest,
amire feltétlenül figyelni kell.
@VA 80386 szigorításai a 80286-hoz képest@N
A 80386 processzor 15 byte-nál hosszabb utasítás dekódolása
esetén EXC 6-ot hoz létre (illegális utasítás kizárás). 16
byte-os hossz azonban csak felesleges prefixek
felhasználásával érhetô el.
LOCK prefixum csak XCHG, BT, BTC, BTS, BTR, ADD, SUB, ADC,
SBB, OR, AND, XOR, INC, DEC, NOT, NEG utasítások elôtt
megengedett. XCHG alatt a processzor automatikusan LOCK
állapotba kerül.
A 80386 biteltoló utasításai modulo 32 veszik figyelembe a
biteltolások értékeit.
@VTanácsok és javaslatok hatékonyabb kód írásához@N
A 80386 CPU barrel-shifter áramkörének segítségével a
biteltolásokat bitszámtól függetlenül azonos idôk alatt
hajtja végre, ezért a 16 bites regiszterek
mentése-visszatöltése rugalmasabb és gyorsabb a 32 bites
regiszter két felének ROR vagy ROL paranccsal való
csereberélésével mint a PUSH-POP páros használatával.
80386DX-nél 32 bites a memória elérése, ami 32 bites
adataink néggyel osztható címre való elhelyezését teszi
célszerûvé (ALIGN 4 parancs). Ügyeljünk arra, hogy SP
értéke mindig legalább páros legyen.
@KFerenczi Viktor@N